﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Xml;
using User.Api.Dto.Sweep;
using Common.Logging;
using OutDbContext;
using System.Threading;
using User.Api.BizExtensions;
using Rmq.Center;
using User.Api.Helpers;
using System.Globalization;
using System.Data.Entity.Validation;

namespace User.Api
{
    /// <summary>
    /// GbkWebService 的摘要说明
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务，请取消注释以下行。 
    // [System.Web.Script.Services.ScriptService]
    public class GbkWebService : System.Web.Services.WebService
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(GbkWebService));
        private static readonly object OrderNoLocker = new object();

        /// <summary>
        /// 缴费
        /// </summary>
        /// <param name="reqXml"></param>
        /// <returns></returns>
        [WebMethod]
        public string DoMicroPay(string reqXml)
        {
            var resFormat = "<res><resultCode>{0}</resultCode><resultDesc>{1}</resultDesc><responseInfo><transactionId>{2}</transactionId><payTime>{3}</payTime><orderNo>{4}</orderNo></responseInfo></res>";
            var resultCode = "1";//0-成功 1-失败 2-输入密码中
            var resultDesc = "";//错误提示
            var orderNo = "";//订单号
            var transactionId = "";//交易流水号
            var payTime = "";//支付时间

            DoMicroPay pay = new DoMicroPay();
            try
            {
                var xDoc = new XmlDocument();
                xDoc.LoadXml(reqXml);
                var node = xDoc.SelectSingleNode("/notification/notificationType");
                pay.notificationType = node == null ? "" : node.InnerText;

                var xNode = xDoc.SelectSingleNode("/notification/notificationInfo/billInfo");

                node = xNode.SelectSingleNode("patientId");
                pay.patientId = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("userIdCard");
                pay.userIdCard = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("userName");
                pay.userName = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("infoSeq");
                pay.infoRmk = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("deptName");
                pay.deptName = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("doctorName");
                pay.doctorName = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("payAmout");
                pay.payAmout = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("authCode");
                pay.authCode = node?.InnerText ?? "";
                if(string.IsNullOrEmpty(pay.authCode))
                {
                    resultCode = "1";
                    resultDesc = "刷卡支付验证码为空!";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }
                if (int.Parse(pay.payAmout) <= 0)
                {
                    resultCode = "1";
                    resultDesc = "缴费金额不能小于等于0!";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }
                using (var ctx = new HzfyWeiXinEntities())
                {
                    orderNo = GenerateNewOrderNo();
                    var newOrder = new MicroPayOrder
                    {
                        //WxUserId = azUser.UserId,
                        PayAmout = pay.payAmout,
                        OrderNo = orderNo,
                        AuthCode = pay.authCode,
                        DeptName=pay.deptName,
                        DoctorName=pay.doctorName,
                        CardNo=pay.patientId,
                        UserIdCard=pay.userIdCard,
                        UserName=pay.userName,
                        InfoRmk=pay.infoRmk,
                        PayType = BillOrderExtensions.PayType.刷卡支付.ToInt32().ToString(),
                        OrderStatus = BillOrderExtensions.OrderStatus.未支付.ToString(),
                        PayState = BillOrderExtensions.PayState.未付款.ToInt32().ToString(),
                        CreateDt = DateTime.Now
                    };
                    ctx.MicroPayOrder.Add(newOrder);
                    ctx.SaveChanges();

                    //RMQ 5分钟后如果还是支付中则设置支付失败
                    var payingTimeoutProducer = new OrderPayingTimeoutProducer();
                    payingTimeoutProducer.Publish(new OrderPayingTimeoutMsg
                    {
                        OrderType = OrderType.刷卡支付订单,
                        OrderId = newOrder.Id
                    }, 5 * 60 * 1000);

                    var outOrderNo = "MP" + newOrder.OrderNo;
                    var result = WeixinPayV3Helper.MicroPay("就诊缴费" + pay.infoRmk, outOrderNo, pay.payAmout.ToInt32().ToString(), pay.authCode,
                        "127.0.0.1", "海珠妇幼保健院");
                    resultCode = result.ResultCode;
                    resultDesc = result.ResultMsg;
                    if (resultCode == "0")
                    {
                        newOrder.WxTransactionId = result.TransactionId;
                        newOrder.PayTime = DateTime.ParseExact(result.TimeEnd,
                            "yyyyMMddHHmmss",
                            CultureInfo.CurrentCulture);
                        newOrder.OrderStatus = BillOrderExtensions.OrderStatus.支付成功.ToInt32().ToString();
                        newOrder.PayState = BillOrderExtensions.PayState.已付款.ToInt32().ToString();
                        newOrder.MicroPayRemark = result.ResultMsg;
                        transactionId = result.TransactionId;
                        payTime = newOrder.PayTime.GetValueOrDefault().ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    else if (resultCode == "1")
                    {
                        newOrder.OrderStatus = BillOrderExtensions.OrderStatus.支付失败.ToInt32().ToString();
                        newOrder.MicroPayRemark = result.ResultMsg;
                        //rmq 撤销订单
                        var orderPayReverseProducer = new OrderPayReverseProducer();
                        orderPayReverseProducer.Publish(new OrderPayReverseMsg
                        {
                            OrderType = OrderType.刷卡支付订单,
                            OrderId = newOrder.Id
                        });
                    }
                    else
                    {
                        newOrder.OrderStatus = BillOrderExtensions.OrderStatus.支付中.ToInt32().ToString();
                        newOrder.MicroPayRemark = result.ResultMsg;
                        ////rmq 查询订单
                        //Logger.InfoFormat("shaoma：{0}", newBillOrder.Id);
                        //var orderPayQueryProducer = new OrderPayQueryProducer();
                        //orderPayQueryProducer.Publish(new OrderPayQueryMsg
                        //{
                        //    OrderType = OrderType.门诊缴费订单,
                        //    OrderId = newBillOrder.Id
                        //}, 5 * 1000);
                    }
                    ctx.SaveChanges();
                }
            }
            catch (DbEntityValidationException e)
            {
                foreach (var eve in e.EntityValidationErrors)
                {
                    Logger.ErrorFormat("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                        eve.Entry.Entity.GetType().Name, eve.Entry.State);
                    foreach (var ve in eve.ValidationErrors)
                    {
                        Logger.ErrorFormat("- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",
                            ve.PropertyName,
                            eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName),
                            ve.ErrorMessage);
                    }
                }
                throw;
            }
            catch (Exception ex)
            {
                Logger.WarnFormat("刷卡支付失败：" + ex.ToString());
                resultCode = "1";
            }
            var res = string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
            return res;
        }

        /// <summary>
        /// 查询订单状态
        /// </summary>
        /// <param name="reqXml"></param>
        /// <returns></returns>
        [WebMethod]
        public string QueryMicroPayOrder(string reqXml)
        {
            var resFormat = "<res><resultCode>{0}</resultCode><resultDesc>{1}</resultDesc><responseInfo><transactionId>{2}</transactionId><payTime>{3}</payTime><orderNo>{4}</orderNo></responseInfo></res>";
            var resultCode = "2";//0-成功 1-失败 2-输入密码中
            var resultDesc = "";//错误提示
            var orderNo = "";//订单号
            var transactionId = "";//交易流水号
            var payTime = "";//支付时间

            DoMicroPay pay = new DoMicroPay();
            try
            {
                var xDoc = new XmlDocument();
                xDoc.LoadXml(reqXml);
                var node = xDoc.SelectSingleNode("/notification/notificationType");
                pay.notificationType = node == null ? "" : node.InnerText;

                var xNode = xDoc.SelectSingleNode("/notification/notificationInfo/billInfo");

                node = xNode.SelectSingleNode("infoSeq");
                pay.infoRmk = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("authCode");
                pay.authCode = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("payAmout");
                pay.payAmout = node?.InnerText ?? "";

                pay.authCode = node?.InnerText ?? "";
                if (pay.notificationType!="8")
                {
                    resultCode = "1";
                    resultDesc = "这是查询订单状态接口";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }
                if (string.IsNullOrEmpty(pay.authCode))
                {
                    resultCode = "1";
                    resultDesc = "刷卡支付验证码为空!";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }
                if (int.Parse(pay.payAmout) <= 0)
                {
                    resultCode = "1";
                    resultDesc = "缴费金额不能小于等于0!";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }

                if (resultCode == "1")
                {
                    var res = string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                    Logger.InfoFormat("QueryMicroPayOrder：{0}", res);
                    return res;
                }
                using (var ctx = new HzfyWeiXinEntities())
                {
                    var order = ctx.MicroPayOrder
                        .FirstOrDefault(x => x.PayAmout == pay.payAmout && x.InfoRmk == pay.infoRmk && x.AuthCode == pay.authCode);
                    if (order == null)
                    {
                        resultCode = "1";
                        resultDesc = "查询不到订单!";
                        var resxml = string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                        Logger.InfoFormat("QueryMicroPayOrder res：{0}", resxml);
                        return resxml;
                    }
                    orderNo = order.OrderNo;
                    var res = WeixinPayV3Helper.OrderQuery("MP" + order.OrderNo);
                    Logger.InfoFormat(" WeixinPayV3Helper.OrderQuery res：{0}", res);

                    if (res.ResultCode == "0")
                    {
                        Logger.InfoFormat("shaoma：{0},{1}", orderNo, res.TradeState);
                        // 交易状态  trade_state  是  String(32) 
                        // SUCCESS—支付成功 
                        // REFUND—转入退款 
                        // NOTPAY—未支付 
                        // CLOSED—已关闭 
                        // REVOKED—已撤销（刷卡支付）
                        // USERPAYING--用户支付中 
                        // PAYERROR--支付失败(其他原因，如银行返回失败)
                        if (res.TradeState.ToUpper() == "USERPAYING")
                        {
                            // 支付中
                            //order.OrderStatus = BillOrderExtensions.OrderStatus.支付中.ToInt32();
                            //order.PayState = BillOrderExtensions.PayState.未付款.ToInt32().ToString();
                            //ctx.SaveChanges();
                            resultCode = "2";
                            resultDesc = "支付中!";

                        }
                        else if (res.TradeState.ToUpper() == "SUCCESS")
                        {
                            // 支付成功
                            order.OrderStatus = BillOrderExtensions.OrderStatus.支付成功.ToInt32().ToString();
                            order.PayState = BillOrderExtensions.PayState.已付款.ToInt32().ToString();
                            order.WxTransactionId = res.TransactionId;
                            order.PayTime = DateTime.ParseExact(res.TimeEnd,
                                "yyyyMMddHHmmss",
                                CultureInfo.CurrentCulture);
                            ctx.SaveChanges();
                            resultCode = "0";
                            resultDesc = "支付成功!";
                            payTime = order.PayTime.GetValueOrDefault().ToString("yyyy-MM-dd HH:mm:ss");
                            transactionId = order.WxTransactionId;
                        }
                        else
                        {
                            // 支付失败
                            order.OrderStatus = BillOrderExtensions.OrderStatus.支付失败.ToInt32().ToString();
                            order.PayState = BillOrderExtensions.PayState.未付款.ToInt32().ToString();
                            ctx.SaveChanges();
                            resultCode = "1";
                            resultDesc = "支付失败!";
                        }
                    }
                    else
                    {
                        Logger.InfoFormat("shaoma-wu：{0}", orderNo);
                        // 支付失败
                        order.OrderStatus = BillOrderExtensions.OrderStatus.支付失败.ToInt32().ToString();
                        order.PayState = BillOrderExtensions.PayState.未付款.ToInt32().ToString();
                        ctx.SaveChanges();
                        resultCode = "1";
                        resultDesc = "支付失败!";
                    }
                }
            }
            catch (DbEntityValidationException e)
            {
                foreach (var eve in e.EntityValidationErrors)
                {
                    Logger.ErrorFormat("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
                        eve.Entry.Entity.GetType().Name, eve.Entry.State);
                    foreach (var ve in eve.ValidationErrors)
                    {
                        Logger.ErrorFormat("- Property: \"{0}\", Value: \"{1}\", Error: \"{2}\"",
                            ve.PropertyName,
                            eve.Entry.CurrentValues.GetValue<object>(ve.PropertyName),
                            ve.ErrorMessage);
                    }
                }
                throw;
            }
            catch (Exception ex)
            {
                Logger.WarnFormat("刷卡支付失败：" + ex.ToString());
                resultCode = "1";
            }

            return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
        }

        [WebMethod]
        public string Reverse(string reqXml)
        {
            //var reqFormat = "<req><infoSeq></infoSeq><authCode></authCode><clinetOrderNo></clinetOrderNo></req>";
            var resFormat = "<res><resultCode>{0}</resultCode><resultDesc>{1}</resultDesc></res>";
            var resultCode = "2";//0-成功 1-失败 2-输入密码中
            var resultDesc = "";//错误提示
            var orderNo = "";//订单号
            var transactionId = "";//交易流水号
            var payTime = "";//支付时间

            DoMicroPay pay = new DoMicroPay();
            try
            {
                var xDoc = new XmlDocument();
                xDoc.LoadXml(reqXml);
                var node = xDoc.SelectSingleNode("/notification/notificationType");
                pay.notificationType = node == null ? "" : node.InnerText;

                var xNode = xDoc.SelectSingleNode("/notification/notificationInfo/billInfo");

                node = xNode.SelectSingleNode("infoSeq");
                pay.infoRmk = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("authCode");
                pay.authCode = node?.InnerText ?? "";

                node = xNode.SelectSingleNode("payAmout");
                pay.payAmout = node?.InnerText ?? "";

                pay.authCode = node?.InnerText ?? "";
                if (pay.notificationType != "8")
                {
                    resultCode = "1";
                    resultDesc = "这是查询订单状态接口";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }
                if (string.IsNullOrEmpty(pay.authCode))
                {
                    resultCode = "1";
                    resultDesc = "刷卡支付验证码为空!";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }
                if (int.Parse(pay.payAmout) <= 0)
                {
                    resultCode = "1";
                    resultDesc = "缴费金额不能小于等于0!";
                    return string.Format(resFormat, resultCode, resultDesc, transactionId, payTime, orderNo);
                }


                using (var ctx = new HzfyWeiXinEntities())
                {
                    var order = ctx.MicroPayOrder
                         .FirstOrDefault(x => x.PayAmout == pay.payAmout && x.InfoRmk == pay.infoRmk && x.AuthCode == pay.authCode);
                    if (order == null)
                    {
                        resultCode = "1";
                        resultDesc = "查询不到订单!";
                        return string.Format(resFormat, resultCode, resultDesc);
                    }
                    //rmq 撤销订单
                    var orderPayReverseProducer = new OrderPayReverseProducer();
                    orderPayReverseProducer.Publish(new OrderPayReverseMsg
                    {
                        OrderType = OrderType.刷卡支付订单,
                        OrderId = order.Id
                    });
                    resultCode = "0";
                    resultDesc = "";
                }

            }
            catch (Exception ex)
            {
                resultCode = "2";
                resultDesc = "异常,请稍后再试！";
            }

            return string.Format(resFormat, resultCode, resultDesc);

        }

        /// <summary>
        /// 生成挂号订单号
        /// </summary>
        /// <returns></returns>
        public string GenerateNewOrderNo()
        {
            var orderNo = "WX" + DateTime.Now.Date.ToString("yyyyMMdd");
            lock (OrderNoLocker)
            {
                orderNo += (DateTime.Now - DateTime.Now.Date).TotalMilliseconds.ToString("00000000");
                Thread.Sleep(1);
            }

            return orderNo;
        }
    }
}
